#pragma once

#include "StdAfx.h"
#include "../dep/include/openssl/sha.h"
#include "BigNumber.h"

namespace Crypt {
	
	class SHA1 
	{
		SHA_CTX mCtx;
		uint8 mDigest[SHA_DIGEST_LENGTH];
		bool mIsFinal;
	public:
		SHA1() : mIsFinal(false) {
			SHA1_Init(&mCtx);
		}

		void clear() {
			SHA1_Final(mDigest, &mCtx);
			memset(&mCtx, NULL, sizeof(SHA_CTX));
			SHA1_Init(&mCtx);
		}

		void getDigest(uint8 (&buffer)[SHA_DIGEST_LENGTH]) {
			if(mIsFinal == false) {
				SHA1_Final(mDigest, &mCtx);
				mIsFinal = true;
			}

			memcpy(buffer, mDigest, SHA_DIGEST_LENGTH);
		}

		const uint8* getDigest() {
			if(mIsFinal == false) {
				SHA1_Final(mDigest, &mCtx);
				mIsFinal = true;
			}

			return mDigest;
		}

		template<typename T>
		void update(const T& value) {
			update(&value, sizeof(T));
		}

		template<>
		void update<BigNumber>(const BigNumber& num) {
			update(num.AsByteArray(), num.GetNumBytes());
		}

		template<>
		void update<std::string>(const std::string& value) {
			update(value.c_str(), value.size());
		}

		void update(const char* value) {
			update(value, strlen(value));
		}

		void update(const void* data, uint32 numBytes) {
			SHA1_Update(&mCtx, data, numBytes);
			mIsFinal = false;
		}
	};

};